/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package tal.drivechain.module.xmlconfig;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import tal.drivechain.chain.NodeInfo;
import tal.drivechain.module.properties.PropertiesManager;
import tal.drivechain.module.properties.KeyValueParser;
import tal.drivechain.parsing.ParsingAid;

/**
 *
 * @author Main
 */
public class ModuleInfo extends NodeInfo {

    ModuleInfo(Node item, PackageInfo packageInfo, PackageConfiguration packageConf) {
        name = item.getAttributes().getNamedItem("name").getNodeValue().replaceAll("\\s+", " ").trim();
        Node nExtends = item.getAttributes().getNamedItem("extends");
        if (nExtends!=null) {
            String sExtends = nExtends.getNodeValue();
            sExtends.replaceAll("\\s+", " ").trim();
            if (!sExtends.equals("")) {
                ModuleInfo inheritedInfo = makeInheritedInfo(sExtends, packageConf);
                properties.addAll(inheritedInfo.getProperties());
            }

        }

        description = "";
        NodeList children = item.getChildNodes();
        for (int i=0; i<children.getLength(); i++) {
            Node currentNode = children.item(i);
            if (currentNode.getNodeName().equals("description")) {
                description = currentNode.getTextContent().replaceAll("\\s+", " ").trim();
            } else if (currentNode.getNodeName().equals("usage")) {
                usage = currentNode.getTextContent().replaceAll("\\s+", " ").trim();
            } else if (currentNode.getNodeName().equals("property")) {
                try {
                    properties.add(new PropertyInfo(currentNode));
                } catch (IllegalArgumentException ie) {
                    throw new IllegalArgumentException("module " + name + ", " + ie.getMessage());
                }
            }
        }
    }

    public String getSyntax() {
        if (properties.size()>0) {
            String out = name + " {";
            String tab = ParsingAid.fillString(" ", out.length());
            out += "\n";

            List<PropertyInfo> ordered = new ArrayList<PropertyInfo>();
            List<PropertyInfo> notordered = new ArrayList<PropertyInfo>();
            notordered.addAll(properties);
            //organize the ordered properties first
            boolean finish = false, found = false;
            int index = 0;
            while (!finish) {
                found = false;
                for (PropertyInfo prop : properties) {
                    if (prop.isOrdered() && prop.getOrderIndex()==index) {
                        ordered.add(prop);
                        notordered.remove(prop);
                        index++;
                        found = true;
                    }
                }
                if (!found) finish = true;
            }
            //
        
            for (PropertyInfo prop : ordered) {
                String sProp = "<" + prop.getParser().getPropertyType() + ">";
                if (prop.isOptional()) sProp = "[" + sProp + "]";
                out += tab + sProp + ";\n";
            }

            for (PropertyInfo prop : notordered) {
                String sProp = "";
                if (!prop.getAttributes().containsKey("open-sequence") && !(prop.getParser() instanceof KeyValueParser)) {
                    sProp = prop.getName() + ": <" + prop.getParser().getPropertyType() + ">";
                    if (prop.isRepeatable()) sProp = sProp + ";...;" + sProp;
                } else if (prop.getAttributes().containsKey("open-sequence")) {
                    sProp = "{" + prop.getParser().getPropertyType() + "}";
                    if (prop.isRepeatable()) sProp = sProp + ";...;" + sProp;
                } else if (prop.getParser() instanceof KeyValueParser) {
                    sProp = "{" + prop.getParser().getPropertyType() + "};...;{" + prop.getParser().getPropertyType() + "}";
                }
                if (prop.isOptional()) sProp = "[" + sProp + "]";
                out += tab + sProp + ";\n";
            }
            out = out + tab + "};";
            return out;
        } else return name + ";";


    }
        
    public PropertiesManager createPropertiesManager() { return new PropertiesManager(properties); }

    private ModuleInfo makeInheritedInfo(String path, PackageConfiguration packageConf) throws IllegalArgumentException {
        //path is in the format of /<package>:<module>

        int div = path.lastIndexOf(":");
        if (div==-1) {
            ModuleInfo ret = packageConf.getModulesInfo().get(path);
            if (ret==null)
                throw new IllegalArgumentException("Can't find inherited module: " + path + " in " + packageConf.getPackageInfo().getName() + ". Make sure " + path + " is placed before " + name + " in the xml file.");
            else return ret;
        } else {
            try {
                String pack = path.substring(0, div);
                String mod = path.substring(div+1);
                URL url = ModuleInfo.class.getResource(pack);
                if (url==null)
                    throw new IllegalArgumentException("Can't find inherited package module xml file: " + pack);

                URI uri = url.toURI();
                PackageConfiguration p = new PackageConfiguration(uri);
                ModuleInfo m = p.getModulesInfo().get(mod);
                if (m==null)
                    throw new IllegalArgumentException("While reading <extends> tag " + path + ": Module " + mod + " was not found.");
                else return m;
            } catch (URISyntaxException ex) {
                throw new IllegalArgumentException("While reading " + path + " : URISyntaxException - " + ex);
            }
        }
    }
}
